package vista;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

import javax.smartcardio.Card;

import cards.Features;
import cards.Features.Cabeza;
import cards.Features.Titulo;
import cards.Features.Cuerpo;
import cards.Features.Orden;
import cards.Features.VelloFacial;
import cards.Monje;

import modelo.BibliotecaModel;
import modelo.Player;
import modelo.Partida;
import modelo.ScriptoriumModel;
import modelo.Sospechoso;
import modelo.UpdateListener;

import tablero.Square;

import controlador.GameController;


public class VistaConsola implements Vista {
	
	private GameController controller;
	private Partida partida;
	private static Scanner input;
	private GameListener oyenteModelo;
	
	public VistaConsola(GameController controlador,Partida partida){
		this.controller=controlador;
		this.partida=partida;
		input= new Scanner(System.in);
		oyenteModelo = new GameListener();
	}
	
	public void start(){
		welcome();
		System.out.print("\n\tEMPEZAR PARTIDA?");
		System.out.print("\n\t1 : SI");
		System.out.print("\n\t2 : NO");
		System.out.print("\n\tOPCION : ");
		int empezar=validarEntrada(1,2);
		if(empezar==1){ 
			controller.empezar();
		}
		else end();
	}
	
	public void welcome(){
		System.out.print("\n\t\t\t*********************************");
		System.out.print("\n\t\t\t**                             **");
		System.out.print("\n\t\t\t**                             **");
		System.out.print("\n\t\t\t**  EL MISTERIO DE LA ABADIA   **");
		System.out.print("\n\t\t\t**                             **");
		System.out.print("\n\t\t\t**                             **");
		System.out.print("\n\t\t\t*********************************");
		System.out.print("\n\n\n");
	}
	
	
	public void imprimeJugadores(){
		System.out.print("\nIMPRIME JUGADORES");
		for(Player j:partida.getPlayerList())
			System.out.print("\n\t"+j);
		System.out.print("\n");
	}
	
	public void meeting(Player j,Square c){                            // Jose hay que arreglar este metodo funciona bien pero es un cristo, hazlo con cuidado
		List<Player> list = new ArrayList<Player>(c.getPlayerList());
		list.remove(j);                                                         // se quita al jugador que va a preguntar
		System.out.print("\n\tENCUENTRO");
		System.out.print("\n\tJugadores aqui: "+list);
		int jugador;
		if(list.size()>1){
			System.out.print("\n\tA quien quieres preguntar?");
			for(int i=1;i<=list.size();i++){
				System.out.print("\n\t"+ i +": "+ list.get(i-1).getNombreJugador());
			}
			System.out.print("\n\tOPCION: ");
			jugador=validarEntrada(0,list.size());
		}
		else jugador=1;
		//TODO voto de silencio
		askQuestion(j,list.get(jugador-1));
	}
	
	
	//Action para dar una carta de la biblioteca 
	public void libraryCardAction() {
		System.out.print("\n\tEstas En la Biblioteca ");
		System.out.print("\n\tDebes cojer una carta especial de aqui y cumplir su penitencia");
		BibliotecaModel p = partida.getLastLibrary();
		System.out.print("\n\tTu Carta es : " + p.toString() );
		System.out.print("\n\tPresciona 1 para continuar");
		validarEntrada(1,1);
	}
	public void scriptoriumCardAction() {
		System.out.print("\n\tEstas En el Scriptorium");
		System.out.print("\n\tDebes cojer una carta especial de aqui y cumplir su penitencia");
		ScriptoriumModel p = partida.getLastScriptoriumCard();
		System.out.print("\n\tTu Carta es : " + p.toString() );
		System.out.print("\n\tPresciona 1 para continuar");
		validarEntrada(1,1);
		
	}
	public void criptaCardAction() {
		System.out.print("\n\tEstas En el  Cripta");
		System.out.print("\n\tDebes cojer una carta especial de aqui y cumplir su penitencia");
		String p = partida.getLastCripta();
		System.out.print("\n\tTu Carta es : " + p.toString() );
		System.out.print("\n\tPresciona 1 para continuar");
		validarEntrada(1,1);
			
	}

	
	public void askQuestion(Player j1,Player j2){	
		System.out.print("\n\tTipo de pregunta: ");
		System.out.print("\n\t1.-¿Cuántos monjes con (1 o 2 rasgos) tienes en (cartas de monje o marcado en la hoja de sospechosos)?");
		System.out.print("\n\t2.-¿Tienes al monje(nombre) en (cartas de monje o marcado en la hoja de sospechosos)?");
		int tipo =validarEntrada(1,2);
		System.out.print("\n\tPreguntar por las cartas en la mano o por monjes marcados en la hoja de sospechosos");
		System.out.print("\n\t1: cartas en la mano");
		System.out.print("\n\t2: monjes marcados en la hoja de sospechosos");
		System.out.print("\n\tOPCION: ");
		int donde =validarEntrada(1,2);
		if(tipo==1){
			System.out.print("\n\tNumero de rasgos a preguntar: ");
			int numRasgos =validarEntrada(1,2);
			List<Features> list=setDifQuestions(numRasgos);
			System.out.print("\n\t:numero de monjes :"+controller.askQuestion(j2, donde, list));
		}
		else if(tipo==2){
			System.out.print("\n\t¿Por que monje quieres preguntar: ");
			String name= input.next();
			boolean answer=this.controller.askQuestion(j1, j2, donde, name);
			if(answer) System.out.print("\n\tSi");
			else System.out.print("\n\tNo");
		}
	}
	
	private List<Features> setDifQuestions(int numRasgos){
		List<Features> list = new ArrayList<Features>();
		for(int i=1;i<=numRasgos;i++){
			Features a = makeQuestion();
			list.add(a);
		}
		return list;
	}

	private Features makeQuestion(){
		int rasgo;
		int tipoRasgo;
		Features a=null;
		System.out.print("\n\tRasgo: ");
		System.out.print("\n\t1:Orden");
		System.out.print("\n\t2:Categoria");
		System.out.print("\n\t3:Cabeza");
		System.out.print("\n\t4:Cuerpo");
		System.out.print("\n\t5:Pelo cara");
		System.out.print("\n\tOPCION: ");
		tipoRasgo=validarEntrada(1,5);
		switch(tipoRasgo){
		case 1:{
			System.out.print("\n\t1:TEMPLARIO;2:FRANCISCANO;3:BENEDICTINO");
			System.out.print("\n\tOPCION: ");
			rasgo=validarEntrada(1,3);
			Orden[] values=Orden.values();
			a = values[rasgo-1];
		}
		break;
		case 2:{
			System.out.print("\n\t1:PADRE;2:HERMANO;3:NOVICIO");
			System.out.print("\n\tOPCION: ");
			rasgo=validarEntrada(1,3);
			Titulo[] values=Titulo.values();
			a= values[rasgo-1];
		}
		break;
		case 3:{
			System.out.print("\n\t1:CAPUCHA;2:CALVO");
			System.out.print("\n\tOPCION: ");
			rasgo=validarEntrada(1,2);
			Cabeza[] values=Cabeza.values();
			a= values[rasgo-1];
		}
		break;
		case 4:{
			System.out.print("\n\t1:DELGADO;2:GORDO");
			System.out.print("\n\tOPCION: ");
			rasgo=validarEntrada(1,2);
			Cuerpo[] values=Cuerpo.values();
			a= values[rasgo-1];
		}
		break;
		case 5:{
			System.out.print("\n\t1:BARBA;2:SIN BARBA");
			System.out.print("\n\tOPCION: ");
			rasgo=validarEntrada(1,2);
			VelloFacial[] values=VelloFacial.values();
			a= values[rasgo-1];
		}
		}//END SWITCH
		System.out.print("\n\trasgo: "+a.toString());
		return a;
	}
	
 	public void end(){
		System.out.print("\n\n\tPARTIDA TERMINADA");
	}
	
	public void readPlayers(){
		int numPlayers;
		System.out.print("\n\t----------------------------------------------------------");
		System.out.print("\n\t---------           COFIGURAR PARTIDA         ------------");
		System.out.print("\n\t----------------------------------------------------------");
		System.out.print("\n\t  # Numero de jugadores(1-6): "      );
		numPlayers=validarEntrada(1,6);
		Set<Integer> colores=new HashSet<Integer>();
		for(int i=1;i<=6;i++)colores.add(new Integer(i));
		for(int i=1;i<=numPlayers;i++){
			System.out.print("\n\t  # Nombre del jugador "+i+": ");
			String nombre = input.next();
			System.out.print("\n\t  # Color jugador : ");
			System.out.print("\n\t  1: ROJO ; 2: VERDE ; 3: AZUL");
			System.out.print("\n\t  4: AMARILLO ; 5: BLANCO ; 6: NEGRO"); 
			System.out.print("\n\t  OPCION: ");
			int eleccion=validarEntrada(colores);
			colores.remove(eleccion);
			controller.addPlayer(nombre, eleccion);
		}
		System.out.print("\n\t----------------------------------------------------------");
		System.out.print("\n\t---------            PARTIDA LISTA              ----------");
		System.out.print("\n\t----------------------------------------------------------");
		System.out.print("\n\n\n\n\n");
	}
	
	private void move(Player j){
		Set<Square> validas=partida.getReachableSquares(j);  // validas a 2 de distancia
		Set<Integer> validas2= new HashSet<Integer>();		 // conjunto de numeros de las casillas validas
		//aqui debo controlar como afectara la ubicacion del usuario con la iteraccion con el mazo especial
		//nuestra funcion debe llamar al metodo con una variable BOOLEANA DE LA OPCION DE LA CARTA
		String p = partida.getPlayerLocation(j).getSquareName().toUpperCase();
		if(getSpecialLocation(p));
		partida.giveDeskCardToPlayer(p,j);
		//controller.deskCardOption(partida.getPlayerLocation(j).getSquareName());
		
		for(Square c:validas) validas2.add(new Integer(c.getNumCasilla()));
		System.out.print("\n\n\t                       MOVIMIENTO                       ");
		System.out.print("\n\t**********************************************************");
		System.out.print("\n\t  Estas en: "+partida.getPlayerLocation(j).getSquareName().toUpperCase());
		System.out.print("\n\t  puedes mover a:\n");
		for(Square c:validas) System.out.print("\n\t   "+ c);
		System.out.print("\n\t**********************************************************");
		System.out.print("\n\n\t   A que NUMERO de casilla quieres mover: ");
		int casilla=validarEntrada(validas2);
		controller.movePlayer(j, casilla);
	}
	
	private boolean getSpecialLocation(String location) {
		if((location== "BIBLIOTECA")||(location== "SCRIPTORIUM")||(location== "CRIPTA"))return true;
		else
		return false;
	}

	/**
	 * We are going to control our turn by a boolean that will compare if we
	 * had moved, So everythime that this menu is called 
	 * the player have just arrive to any room of the game and his movement trigger 
	 * will be off 	
	 */
	public void turnOf(Player j) {
		boolean turnEnd=false;
		while(!j.hasMoved()||!turnEnd){
			System.out.print("\n\n");
			System.out.print("\n\t                     TURNO DE: "+j.getNombreJugador().toUpperCase());
			System.out.print("\n\t**********************************************************");
			System.out.print("\n\t TURNO "+partida.getTurno()+", MISA "+partida.getMisa());
			System.out.print("\n\t ESTAS EN: "+j.getUbication().getSquareName());
			System.out.print("\n\t OPCIONES:");
			if(!j.hasMoved()) System.out.print("\n\t\t\t1.- MOVER");
			System.out.print("\n\t\t\t2.- VER CARTAS DE MONJE");
			System.out.print("\n\t\t\t3.- VER HOJA DE SOSPECHOSOS");
			if(j.hasMoved())System.out.print("\n\t\t\t4.- FIN DE TURNO	");
			System.out.print("\n\t**********************************************************");
			System.out.print("\n\t\tOPCION: ");
			int opcion;
			if(!j.hasMoved()) opcion = this.validarEntrada(1, 3);
			else opcion = this.validarEntrada(2, 4);
			switch (opcion)
			{
			case 1: move(j);
				break;
			case 2: muestraCartasMonje(j);
				break;	
			case 3: muestraHojaSospechosos(j);
				break;
			case 4: {
				turnEnd=true;
				System.out.print("\n\t\tFIN DE TURNO DE "+j.getNombreJugador().toUpperCase());
			}
			}
		}
	}
//TODO: puede petar procedimiento hay que colocar excepciones
	public void muestraCartasMonje(Player j){
		Set<cards.Card> set=j.getCartasMonje();
		System.out.print("\n\n\t                      CARTAS DE MONJE                         ");	
		System.out.print("\n\t****************************************************************");
		for(cards.Card monje : set) System.out.print("\n\t  "+monje                                 );
		System.out.print("\n\t****************************************************************");
	}
	
	public void muestraHojaSospechosos(Player j){
		boolean exit=false;
		Set<Sospechoso> set=j.getHojaSospechosos();
		while(!exit){
			System.out.print("\n\n\t                             HOJA DE SOSPECHOSOS                               ");
			System.out.print("\n\t*********************************************************************************");
			for(Sospechoso sopechoso : set) System.out.print("\n\t  "+sopechoso                                     );
			System.out.print("\n\t*********************************************************************************");
			System.out.print("\n\t    1.- Anotar algo acerca de un sospechoso");
			System.out.print("\n\t    2.- Leer anotaciones");
			System.out.print("\n\t    3.- Salir");
			System.out.print("\n\t    Opcion: ");
			int option = validarEntrada(1,3);
			switch(option){
			case 1: writeDown(j);
			break;
			case 2: readNotes(j);
			break;
			case 3: exit =true;
			}
		}
	}
	
	private void readNotes(Player j) {
		for(Sospechoso sopechoso : j.getHojaSospechosos()) System.out.print("\n\t  "+sopechoso+" "+sopechoso.getAnnotation());
		
	}

	private void writeDown(Player j){
		System.out.print("\n\t  nº de sospechoso: ");
		int id = validarEntrada(1,24);
		System.out.print("\n\t  anotacion: ");
		String annotation="";
		this.controller.writeDown(j, id, annotation);
	}
	
	
	public void endOfTheTurn(){
		System.out.print("\nFIN TURNO");
	}
	
	
	private int validarEntrada(int inf,int sup) throws InputMismatchException{
		boolean salir=false;
		int valor=0;
		do{
			boolean ok=false;
			do{
				try{
					valor=input.nextInt();
					ok=true;
				}
				catch(InputMismatchException e){
					input.next();
					System.out.print("\n\t Introduce un entero entre "+inf+" y "+sup+": ");
				} 
			}
			while(!ok);
			if((valor>=inf)&&(valor<=sup))salir=true;
			else{
				System.out.print("\n\t valor no valido");
				System.out.print("\n\t elija entre "+inf+"-"+sup+": ");
			}
		}
		while(!salir);
		return valor;
	}
	
	/**
	 * Por Estetica y Respeto al patron seguido esta Clase que puede tener acceso a los jugadores Solo creara un ARRYLIST de numero de Cartas para que la partida pueda buscarla en cada clase de cada jugador
	 * @param j
	 * @param switchingCard
	 * @param numOfCardsToExchange
	 * @return
	 */
	//TODO: HACER METODO DE INTERCAMBIO
	
	public void getNumOfExCards(Player j) {
		int p=partida.getCardsForMisa();
		Set<cards.Card> set=j.getCartasMonje();
		List<Integer> reference = new ArrayList<Integer>();
		System.out.println("Vuelta a la Capilla " );
		System.out.println("Debes Intercambiar " + p + "\n\t Elige de tu repositoro de Cartas Cuales deseas Cambiar "+
		"si no tienes Cartas al momento de este menu el sistema saltara tu turno ");
		if (!j.getCartasMonje().isEmpty())
			for(cards.Card monje : set) System.out.print("\n\t  "+monje);
		
//		while (reference.size()<numOfCardsToExchange||!set.isEmpty())
//			for(Monje monje : set) System.out.print("\n\t  "+monje);
//		System.out.println("Elige 1 a 1 y presciona ENTER despues de elegir cada Monje estos seguiran Apareciendo!");
//		int p=validarEntrada(0,j.getCartasMonje().size());
//		partida.setNewCardToTempCards(p,j);


	}
	private int validarEntrada(Set<Integer> conjuntoValores) throws InputMismatchException{
		boolean salir=false;
		int valor=0;
		do{
			boolean ok=false;
			do{
				try{
					valor=input.nextInt();
					ok=true;
				}
				catch(InputMismatchException e){
					input.next();
					System.out.print("\n\tIntroduce un entero entre :"+conjuntoValores);
				}
			}
			while(!ok);
			if(conjuntoValores.contains(valor))salir=true;
			else{
				System.out.print("\n\t valor no valido");
				System.out.print("\n\t elija entre "+conjuntoValores+": ");
			}
		}
		while(!salir);
		return valor;
	}
	
	public GameListener getGameListener(){
		return oyenteModelo;
	}
	
	private class GameListener implements UpdateListener {

		@Override
		public void ubicacionActualizada(Player j) {
			// TODO Auto-generated method stub
			System.out.print("\n\tEVENTO: Actualizada ubicacion de: "+j.getNombreJugador().toUpperCase()+" a la casilla "+j.getUbication().getSquareName().toUpperCase()+"\n");	
		}
		
		public void newPlayer(Player j){
			System.out.print("\n\tEVENTO: Nuevo jugador : "+j+"\n");
		}

		@Override
		public void twoPlayersHere(Player j,Square c) {
			// TODO Auto-generated method stub
			meeting(j,c);
		}

		@Override
		public void playerTurn(Player j) {
			// TODO Auto-generated method stub
			turnOf(j);
		}

		@Override
		public void partidaEmpezada() {
			readPlayers();	
		}

		@Override
		public void movements(Player j, Set<Square> casillasValidas) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void cardsExchangeMode(Player j) {
			getNumOfExCards(j);
			
		}

		@Override
		public void deskCardEventLibrary(Player j) {
			libraryCardAction();
			
		}

		@Override
		public void deskCardEventScriptorium(Player j) {
			scriptoriumCardAction();
			
		}

		@Override
		public void deskCardEventCripta(Player j) {
			criptaCardAction();
			
		}
	} //PRIVATE CLASS OYENTEMODELO


	

	
	


}
